home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
fish
/
726-750
/
729
/
dsound
/
source
/
dsound.c
next >
Wrap
C/C++ Source or Header
|
1995-03-18
|
18KB
|
679 lines
/**************************************************************************/
/* DSound V1.20 */
/* Copyright 1991-1992 by Dave Schreiber, All Rights Reserved */
/* */
/* To compile: */
/* lc -Lcd -v -tr DSound Play Mem */
/* or */
/* lmk */
/* */
/* Revision history: */
/* V1.20 - Added the ability to stop DSound by typing CTRL-C, and */
/* added the switch '-w', which keeps the DSound window from */
/* opening. */
/* V1.10 - Added the ability to play a sound sample repeatedly (in a */
/* loop). */
/* July 11, 1992 */
/* V1.00 - Added a new module (Mem.c) which allows a sample to be */
/* loaded entirely into memory, so samples can be played from */
/* floppy disk without first copying to a hard or RAM drive. */
/* DSound also can now play a single channel of a stereo */
/* out of two speakers. The small window, used to let the */
/* user abort a playing sample, as been redone (DSound also */
/* now responds instantly when the user clicks on the Close */
/* gadget). DSound now checks a given 8SVX sample to make */
/* sure that it is actually a valid sample. Finally, DSound */
/* has been made pure (residentiable). */
/* Second release (April 16, 1992) */
/* V0.94a - Can now play a mono sample out of both speakers at the */
/* same time (using the -2 switch). */
/* March 27, 1992 (a little later) */
/* V0.93a - Now handles stereo sound samples. Either the right or */
/* left, or both, stereo channels can be played. Also split */
/* off the code that actually plays the sound sample into a */
/* separate source file (Play.c). */
/* March 27, 1992 */
/* V0.92a - Now gets the length of the sound sample from the head of */
/* the BODY chunk, instead of the VHDR (a workaround to a bug */
/* in the Perfect Sound software that would sometimes store */
/* an incorrect length in the VHDR chunk of a sound sample). */
/* November 4, 1991 */
/* V0.91a - First release (September 11, 1991) */
/**************************************************************************/
#include <exec/types.h>
#include <exec/exec.h>
#include <devices/audio.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>
#include <stdlib.h>
#include <stdio.h>
#include "dsound.h"
#include <proto/intuition.h>
#include <proto/exec.h>
#include <proto/dos.h>
char filename[140];
#define DEF_BUF_SIZE 30000
void InterpretArgs(int argc,char *argv[]);
BOOL noFilter=FALSE;
UBYTE volume=0;
UWORD speed=0;
ULONG bufSize=DEF_BUF_SIZE;
void filter_on(void);
void filter_off(void);
char *version="$VER: DSound V1.20 (23.8.92)";
char *copyright="Copyright 1991-1992 by Dave Schreiber, All Rights Reserved";
struct IntuitionBase *IntuitionBase=NULL;
struct GfxBase *GfxBase=NULL;
struct Window *window=NULL;
BPTR file=NULL;
channel audioChannel=UNSPECIFIED;
BOOL bothChan=FALSE;
BOOL readAll=FALSE;
BOOL loop=FALSE;
/*The window definition*/
struct NewWindow newWindow = {
124,31,
250,56,
0,1,
CLOSEWINDOW,
SMART_REFRESH|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE,
NULL,
NULL,
"DSound V1.20",
NULL,
NULL,
5,5,
640,200,
WBENCHSCREEN
};
/*This determines whether or not the window will be opened*/
BOOL openTheWdw=TRUE;
ULONG signalMask=SIGBREAKF_CTRL_C;
main(int argc,char *argv[])
{
struct Voice8Header vhdr;
UBYTE foo2[5];
UBYTE foo[5];
ULONG chan;
ULONG sampleLength;
ULONG lock;
char *chanStr;
filename[0]=NULL;
/*Get and interpret the command-line arguments*/
InterpretArgs(argc,argv);
/*Exit if there was no sound sample specified*/
if(filename[0]==NULL)
{
WriteMsg("Please specify the name of a sound sample\n");
cleanup(75);
}
/*Open the file*/
file=Open(filename,MODE_OLDFILE);
if(file==NULL)
{
WriteMsg("Couldn't open the file\n");
cleanup(100);
}
/*If the user hasn't told us not to open the window*/
if(openTheWdw)
{
/*Open libraries*/
GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L);
IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0L);
if(GfxBase==NULL || IntuitionBase==NULL)
{
WriteMsg("A shared library could not be opened\n");
cleanup(50);
}
/*Get the size of the title bar font in a rather illegal way */
/*Note: programmers at C= should put a GetDefTitleBarFontHeight() */
/*function into Intuition before complaining to me about the following*/
/*code. */
lock=LockIBase(0L);
newWindow.Height=IntuitionBase->ActiveScreen->Font->ta_YSize+3;
UnlockIBase(lock);
window=OpenWindow(&newWindow);
if(window==NULL)
cleanup(110);
signalMask|=1<<window->UserPort->mp_SigBit;
}
/*Read the header*/
Read(file,foo,4);
Seek(file,4,OFFSET_CURRENT);
Read(file,foo2,4);
foo[4]=foo2[4]=NULL;
/*Check the header's validity, more or less*/
if((strcmp(foo,"FORM")!=0) || (strcmp(foo2,"8SVX")!=0))
{
WriteMsg("Not a valid IFF 8SVX sound sample file.\n");
cleanup(120);
}
if(strcmp(FindChunk(file,"VHDR"),"VHDR")!=0)
{
WriteMsg("Couldn't find the 8SVX header (VHDR).\n");
cleanup(130);
}
/*Skip past the chunk size*/
Seek(file,4,OFFSET_CURRENT);
/*Get the VHDR*/
Read(file,&vhdr,sizeof(struct Voice8Header));
/*Check for compression*/
if(vhdr.sCompression!=0)
{
WriteMsg("Can't play a compressed sample!\n");
cleanup(400);
}
/*Get the CHAN chunk (which will tell us if the sample is stereo, or,*/
/*if it is mono, which speaker it should be played out of*/
chanStr=FindChunk(file,"CHAN");
if(strcmp(chanStr,"CHAN")==0)
{
/*Skip past chunk size*/
Seek(file,4,OFFSET_CURRENT);
Read(file,&chan,sizeof(long));
/*The information we're looking for consists of one longword*/
switch(chan)
{
case 2: /*Mono sample, left speaker*/
if(bothChan)
/*Play out of both channels if -2 used*/
audioChannel=MONO_BOTH;
else
if(audioChannel==UNSPECIFIED)
audioChannel=MONO_LEFT;
break;
case 4: /*Mono sample, right speaker*/
if(bothChan)
/*Play out of both channels if -2 used*/
audioChannel=MONO_BOTH;
else
if(audioChannel==UNSPECIFIED)
audioChannel=MONO_RIGHT;
break;
case 6: /*Stereo*/
switch(audioChannel)
{
/*This reconciles a user's choice with the fact that the*/
/*sample is in stereo*/
/*Play left stereo channel*/
case MONO_LEFT:
if(bothChan)
audioChannel=STEREO_LEFT_BOTH;
else
audioChannel=STEREO_LEFT;
break;
/*Play right stereo channel*/
case MONO_RIGHT:
if(bothChan)
audioChannel=STEREO_RIGHT_BOTH;
else
audioChannel=STEREO_RIGHT;
break;
/*Play both channels*/
case UNSPECIFIED:
audioChannel=STEREO;
break;
}
break;
}
/*Find the start of the BODY chunk*/
chanStr=FindChunk(file,"BODY");
}
else
{
chan=0;
if(bothChan)
audioChannel=MONO_BOTH;
}
if(strcmp(chanStr,"BODY")!=0)
{
WriteMsg("Couldn't find body of sample.\n");
cleanup(140);
}
if(noFilter)
filter_off();
/*Get the length of the sample*/
Read(file,(char *)&sampleLength,4);
SetSignal(0,0);
/*Play the sample by choosing the appropriate player function*/
switch(audioChannel)
{
case MONO_LEFT:
case MONO_RIGHT:
case UNSPECIFIED:
/*Simple mono playback*/
playMonoSample(file,audioChannel,&vhdr,sampleLength);
break;
case MONO_BOTH:
/*Mono playback using both speakers*/
playMonoTwice(file,audioChannel,&vhdr,sampleLength);
break;
case STEREO_RIGHT:
/*Right stereo channel*/
audioChannel=MONO_RIGHT;
Seek(file,sampleLength/2,OFFSET_CURRENT);
playMonoSample(file,audioChannel,&vhdr,sampleLength/2);
break;
case STEREO_RIGHT_BOTH:
/*Right stereo channel out of both speakers*/
audioChannel=MONO_RIGHT;
Seek(file,sampleLength/2,OFFSET_CURRENT);
playMonoTwice(file,audioChannel,&vhdr,sampleLength/2);
break;
case STEREO_LEFT:
/*Left stereo channel*/
audioChannel=MONO_LEFT;
playMonoSample(file,audioChannel,&vhdr,sampleLength/2);
break;
case STEREO_LEFT_BOTH:
/*Left stereo channel out of both speakers*/
audioChannel=MONO_LEFT;
playMonoTwice(file,audioChannel,&vhdr,sampleLength/2);
break;
case STEREO:
/*Stereo sample (both channels)*/
playStereoSample(file,audioChannel,&vhdr,sampleLength/2,filename);
break;
}
if(noFilter)
filter_on();
/*Free allocated resources and exit*/
cleanup(0);
}
/* Get an audio channel */
struct IOAudio *GetAudioChannel(ULONG bufferSize,UBYTE *allocationMap)
{
struct IOAudio *aIOB;
void *audioBuf;
struct Port *aPort;
aPort=(struct Port *)CreatePort("dsound",0);
if(aPort==NULL)
return(NULL);
/* Allocate the chip memory buffer for the channel */
audioBuf=(void *)AllocMem(bufferSize,MEMF_CHIP);
if(audioBuf==NULL)
{
DeletePort(aPort);
return(NULL);
}
/* Allocate an IOAudio structure*/
aIOB=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
if(aIOB==NULL)
{
DeletePort(aPort);
FreeMem(audioBuf,bufferSize);
return(NULL);
}
/* Set up the IOAudio to allocate the command channel */
aIOB->ioa_Request.io_Message.mn_Node.ln_Pri=0;
aIOB->ioa_Request.io_Message.mn_ReplyPort=aPort;
aIOB->ioa_Data=allocationMap;
aIOB->ioa_Length=4;
aIOB->ioa_Request.io_Command=ADCMD_ALLOCATE;
/*Open the audio device*/
OpenDevice("audio.device",0,(struct IORequest *)aIOB,0);
if(aIOB->ioa_AllocKey==0)
{ /*There was an error*/
DeletePort(aPort);
FreeMem(audioBuf,bufferSize);
FreeMem(aIOB,sizeof(struct IOAudio));
return(NULL);
}
else
{
/* Set up the IOAudio for writes */
aIOB->ioa_Request.io_Command=CMD_WRITE;
aIOB->ioa_Request.io_Flags=ADIOF_PERVOL;
aIOB->ioa_Data=audioBuf;
aIOB->ioa_Length=bufferSize;
return(aIOB);
}
}
/* Free an allocated audio channel */
void FreeAudioChannel(struct IOAudio *aIOB)
{
if(aIOB==NULL)
return;
/* Free the audi obuffer */
if(aIOB->ioa_Data!=NULL)
FreeMem(aIOB->ioa_Data,aIOB->ioa_Length);
/* Free the audio channel */
aIOB->ioa_Request.io_Command=ADCMD_FREE;
BeginIO((struct IORequest *)aIOB);
WaitIO((struct IORequest *)aIOB);
DeletePort(aIOB->ioa_Request.io_Message.mn_ReplyPort);
/* Close the audio channel */
CloseDevice((struct IORequest *)aIOB);
/* Free the IOAudio structure */
FreeMem(aIOB,sizeof(struct IOAudio));
return;
}
/* Initialize an IOAudio's volume, period, and set the number of cycles */
/* to one */
void InitAudioChannel(struct IOAudio *aIOB,UWORD volume,UWORD period)
{
aIOB->ioa_Period=period;
aIOB->ioa_Volume=volume;
aIOB->ioa_Cycles=1;
return;
}
/* Duplicate an IOAudio structure */
struct IOAudio *DuplicateAudioChannel(struct IOAudio *OrigIOB)
{
struct IOAudio *aIOB;
void *audioBuf;
if(OrigIOB==NULL)
return(NULL);
/* Allocate the alternate buffer */
audioBuf=(void *)AllocMem(OrigIOB->ioa_Length,MEMF_CHIP);
if(audioBuf==NULL)
return(NULL);
/*Allocate the IOAudio structure*/
aIOB=(struct IOAudio *)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR);
if(aIOB==NULL)
{
FreeMem(audioBuf,OrigIOB->ioa_Length);
return(NULL);
}
/*Copy the original IOAudio's contents to the new one*/
CopyMem(OrigIOB,aIOB,sizeof(struct IOAudio));
/*Except for the buffer pointer, of course*/
aIOB->ioa_Data=audioBuf;
return(aIOB);
}
/*Delete a duplicated IOAudio*/
void DeleteDuplication(struct IOAudio *aIOB)
{
if(aIOB != NULL)
{
/* Free the memory for the buffer and IOAudio */
if(aIOB->ioa_Data != NULL)
FreeMem(aIOB->ioa_Data,aIOB->ioa_Length);
FreeMem(aIOB,sizeof(struct IOAudio));
}
return;
}
/* Load an IOAudio's buffer from an open file */
ULONG LoadAudioBuffer(BPTR file,struct IOAudio *aIOB,ULONG toRead)
{
if(toRead==0)
return(0);
if(file==0L)
getLeft(aIOB->ioa_Data);
else if(file==4L)
getRight(aIOB->ioa_Data);
else
aIOB->ioa_Length=Read(file,aIOB->ioa_Data,toRead);
return(aIOB->ioa_Length);
}
/*Find the beginning of an IFF chunk. This routine will search for that*/
/*chunk's name, and if found, will leave the file cursor at the chunk size*/
/*field. If the chunk isn't found, the file cursor will be left at the*/
/*size field of the BODY chunk, if there was one*/
char *FindChunk(BPTR file,char *string)
{
static char buf[5];
long len,actLen;
buf[4]=NULL;
actLen=Read(file,buf,4);
while(strcmp(string,buf)!=0 && strcmp(buf,"BODY")!=0 && actLen > 0)
{
Read(file,(char *)&len,4);
Seek(file,len,OFFSET_CURRENT);
actLen=Read(file,buf,4);
}
return(buf);
}
/* Interpret the command line arguments */
void InterpretArgs(int argc,char *argv[])
{
int i;
for(i=1;i<argc;i++)
{
if(argv[i][0]=='-')
switch(argv[i][1])
{
/* Read the entire sample into memory before playing */
case 'm':
case 'M':
readAll=TRUE;
break;
/* Use the left channel */
case 'l':
case 'L':
audioChannel=MONO_LEFT;
break;
/* Use the right channel */
case 'r':
case 'R':
audioChannel=MONO_RIGHT;
break;
/*Play a mono sample out of both speakers*/
case '2':
bothChan=TRUE;
break;
/* Switch off the low-pass filter while the sample is playing */
case 'f':
case 'F':
noFilter=TRUE;
break;
/* Play a sample at a given speed */
case 's':
case 'S':
speed=atol(&argv[i][2]);
if(speed > 28000)
speed=0;
break;
/* The volume at which the sample should be played */
case 'v':
case 'V':
volume=atol(&argv[i][2]);
if(volume > 64)
volume=0;
break;
/* The size of the chip RAM buffers */
case 'b':
case 'B':
bufSize=(atol(&argv[i][2])+1)&(~1);
if(bufSize==0)
bufSize=DEF_BUF_SIZE;
break;
/* Loop the sample */
case 'o':
case 'O':
loop=TRUE;
break;
case 'w':
case 'W':
openTheWdw=FALSE;
break;
}
else if(argv[i][0]=='?')
{
/*On-line help*/
WriteMsg("DSound V1.20 ©1991-1992 by Dave Schreiber\n");
WriteMsg("Usage:\n");
WriteMsg(" DSound <options> <filename>\n");
WriteMsg("Where the options are:\n");
WriteMsg(" -l -- Play the sample using the left speaker\n");
WriteMsg(" -r -- Play the sample using the right speaker\n");
WriteMsg(" -2 -- Play the sample using both speakers\n");
WriteMsg(" -f -- Shut off the low-pass filter\n");
WriteMsg(" -m -- Load the entire sample into memory\n");
WriteMsg(" -o -- Play the sample continuously (loop)\n");
WriteMsg(" -w -- Do not open the DSound window\n");
WriteMsg(" -s<speed> -- Play the sample at the given speed (samples/sec)\n");
WriteMsg(" -v<volume> -- Play the sample at the given volume (0-64)\n");
WriteMsg(" -b<bufsize> -- Use a buffer of size <bufsize> (default is 30K)\n");
exit(0);
}
else /*Otherwise, the argument is a filename */
strcpy(filename,argv[i]);
}
}
/*Switch on the low-pass filter */
void filter_on()
{
*((char *)0x0bfe001)&=0xFD;
}
/*Switch off the low-pass filter*/
void filter_off()
{
*((char *)0x0bfe001)|=0x02;
}
/*Write a message to the CLI*/
void WriteMsg(char *errMsg)
{
Write(Output(),errMsg,strlen(errMsg));
}
/*Take a file handle and that handle's filename, and open that file again*/
/*The position in the second file in set to the position in the first */
/*file (so that the two file handles are essentially identical)*/
/*This requires that the first file was opened in a shared mode, like */
/*MODE_OLDFILE*/
BPTR dupFileHandle(BPTR origFile,char *filename)
{
BPTR dupFile;
dupFile=Open(filename,MODE_OLDFILE);
if(dupFile==NULL)
return(NULL);
Seek(dupFile,getPosInFile(origFile),OFFSET_BEGINNING);
return(dupFile);
}
/*Get the current position in a file*/
ULONG getPosInFile(BPTR file)
{
LONG position;
position=Seek(file,0,OFFSET_CURRENT);
return((ULONG)position);
}
/* Free allocated resources */
void cleanup(int err)
{
/*If the entire sample was read into memory, this will delete whatever*/
/*part of the sample still remains in memory*/
deleteLeft();
deleteRight();
if(file!=NULL)
Close(file);
if(window!=NULL)
CloseWindow(window);
if(GfxBase!=NULL)
CloseLibrary((struct Library *)GfxBase);
if(IntuitionBase!=NULL)
CloseLibrary((struct Library *)IntuitionBase);
exit(err);
}
#ifdef LATTICE
int CXBRK(void) {return(0);}
int chkabort(void) {return(0);}
#endif
/*End of DSound.c*/